/**
 * @file port_ble_gatt_client.c
 * @brief 
 * @author dotc (dotchan@qq.com)
 * @date 2025-01-21
 * 
 * @copyright Copyright (c) 2025 by 深圳市鹏天微智能科技有限公司, All Rights Reserved.
 */

#if defined(CONFIG_PORT_BLE_ENABLE)

/* ==================== [Includes] ========================================== */

// 单独控制本文件功能的优先级
#define XF_LOG_LEVEL            CONFIG_PORT_BLE_GATT_LOG_LEVEL

#include "xf_ble_gatt_client.h"
#include "xf_ble_gap.h"
#include "xf_utils.h"
#include "xf_init.h"
#include "xf_task.h"
#include "xf_ble_port_utils.h"
#include "port_ble_common.h"

#include "bledef.h"
#include "drvs.h"
#include "prf_api.h"
#include "gatt_api.h"

/* ==================== [Defines] =========================================== */

#define TAG "port_ble_gattc"

#define PORT_GATT_ATT_VAL_INFO_INDEX_INVALID    (UINT8_MAX)

/* ==================== [Typedefs] ========================================== */

/* ==================== [Static Prototypes] ================================= */

xf_err_t _default_ble_gattc_evt_cb(
    xf_ble_gattc_evt_t event,
    xf_ble_gattc_evt_cb_param_t *param);

/* ==================== [Static Variables] ================================== */

static xf_ble_gattc_evt_cb_t s_ble_gattc_evt_cb = _default_ble_gattc_evt_cb;

static uint8_t const s_map_gattc_write_tyep[] = 
{
    [XF_BLE_GATT_WRITE_TYPE_NO_RSP] = GATT_WRITE_NO_RESPONSE,
    [XF_BLE_GATT_WRITE_TYPE_WITH_RSP] = GATT_WRITE,
};

/* ==================== [Macros] ============================================ */

#define port_gatt_handle_offset(svc_start_hdl, hdl)    ((hdl) - (svc_start_hdl))

/* ==================== [Global Functions] ================================== */

/**
 * @brief BLE GATTC 客户端注册
 *
 * @param[in] app_uuid 要注册的客户端 (应用) 的 UUID ，见 @ref xf_ble_uuid_info_t
 * @param[out] app_id 客户端 (应用) ID
 * @return xf_err_t
 *      - XF_OK                 成功
 *      - XF_FAIL               失败
 *      - (OTHER)               @ref xf_err_t
 */
xf_err_t xf_ble_gattc_app_register(
    xf_ble_uuid_info_t *app_uuid, uint8_t *app_id)
{
    struct gapm_dev_config cfg_copy = *port_ble_dev_cfg_record_get();
    cfg_copy.gap_role |= GAP_ROLE_CENTRAL;

    bd_addr_t * local_addr = port_ble_get_local_addr();

    gapm_set_dev(&cfg_copy, local_addr, NULL);
    port_msg_evt_get_with_check_and_clear(PORT_MSG_EVT_BLE_SET_ROLE, 10);
   
    port_ble_dev_cfg_record_set(&cfg_copy);

    *app_id  = port_gatt_app_id_alloc();
    if(app_id == XF_BLE_GATT_APP_ID_INVALID)
    {
        return XF_ERR_RESOURCE;
    }
    return XF_OK;
}

/**
 * @brief BLE GATTC 客户端注销
 *
 * @param app_id 客户端 ID
 * @return xf_err_t
 *      - XF_OK                 成功
 *      - XF_FAIL               失败
 *      - (OTHER)               @ref xf_err_t
 */
xf_err_t xf_ble_gattc_app_unregister(uint8_t app_id)
{
    /* TODO 暂不支持注销 */
    return XF_ERR_NOT_SUPPORTED;
}

/**
 * @brief BLE GATTC 搜寻服务（指定 UUID 或 尝试搜寻所有服务）
 *
 * @param app_id 客户端 ID (应用 ID )
 * @param conn_id 连接 ID (链接 ID )
 * @param start_handle 服务起始句柄
 * @param end_handle 服务结束句柄
 * @param service_uuid 指定搜寻的服务的 UUID，见 @ref xf_ble_uuid_info_t
 *      - NULL      搜寻所有服务
 *      - (OTHER)   指定搜寻的服务的 UUID ( 注意 UUID 需要为有效值，如不能为 0 )
 * @param [in,out] service_set_info 传入将存储服务集合信息的地址。
 *  见 @ref xf_ble_gattc_service_found_set_t ，例：
 * @code
 *  xf_ble_gattc_service_found_set_t service_set_info = {0};
 *  ......
 *  xf_ble_gattc_discover_service(s_app_id, s_conn_id, NULL, &service_set_info);
 * @endcode
 * @return xf_err_t
 *      - XF_OK                 成功
 *      - XF_FAIL               失败
 *      - (OTHER)               @ref xf_err_t
 */
xf_err_t xf_ble_gattc_discover_service(
    uint8_t app_id, uint16_t conn_id,
    uint16_t start_handle,
    uint16_t end_handle,
    xf_ble_uuid_info_t *service_uuid,
    xf_ble_gattc_service_found_set_t *service_set_info)
{
    XF_ASSERT(service_set_info != NULL, XF_ERR_INVALID_ARG,
             TAG, "service_set_info == NULL");
    XF_ASSERT(
            (start_handle != XF_BLE_ATTR_HANDLE_INVALID) 
        &&  (end_handle != XF_BLE_ATTR_HANDLE_INVALID), XF_ERR_INVALID_ARG,
        TAG, "handle([%#04X,%#04X]) invalid![0x0001,0xFFFF]", start_handle, end_handle);
    
    xf_ble_gattc_service_found_t *svc_set = NULL;
    if(service_uuid == NULL)
    {
        XF_LOGD(TAG,"DISC ALL SVC START");   
        gatt_disc(conn_id, GATT_DISC_ALL_SVC, start_handle, end_handle, 0, NULL);

        /* 检查是否有发现所有服务完成的事件 */
        port_msg_evt_get_with_check_and_clear( 
            PORT_MSG_EVT_BLE_GATT_DISC_SVC_ALL_CMPLT, 30); 

        port_msg_info_t **list_msg_info = port_msg_info_list_get();
        
        uint8_t index = 0;
        uint8_t num = 0;
        /* 遍历事件信息列表，获取发现的服务数量 */
        for(;index < MSG_INFO_LIST_MAX_CNT; index++)
        {
            if(list_msg_info[index] == NULL)
            {
                continue;
            }    
            if( (list_msg_info[index]->grp_type == PORT_MSG_GRP_TYPE_GATT)
            &&  (list_msg_info[index]->msg_index == MSG_IDX(GATT_DISC_SVC_IND)) )
            {
                ++num;
            }
        }

        service_set_info->cnt = num;
        if (num == 0)
        {
            XF_LOGD(TAG,"DISC NO SVC");   
            return XF_OK;
        }

        svc_set = xf_malloc(num * sizeof(xf_ble_gattc_service_found_t));
        XF_LOGD(TAG,">>>>> malloc:%p", svc_set);   
        index = 0;
        num = 0;
        /* 检查消息的信息列表是否有匹配的 消息类型及消息索引 */
        for(;index < MSG_INFO_LIST_MAX_CNT; index++)
        {
            if(list_msg_info[index] == NULL)
            {
                continue;
            }    
            if( (list_msg_info[index]->grp_type == PORT_MSG_GRP_TYPE_GATT)
            &&  (list_msg_info[index]->msg_index == MSG_IDX(GATT_DISC_SVC_IND)) )
            {
                struct gatt_disc_svc_ind *param_disc = (struct gatt_disc_svc_ind *)list_msg_info[index]->param; 

                XF_LOGD(TAG, "DISC SVC:hdl[%d,%d],uuid_len:%d",
                    param_disc->start_hdl,
                    param_disc->end_hdl,
                    param_disc->uuid_len);

                svc_set[num].chara_set_info.cnt = 0;
                svc_set[num].chara_set_info.set = NULL;
                svc_set[num].start_hdl = param_disc->start_hdl;
                svc_set[num].end_hdl = param_disc->end_hdl;
                svc_set[num].uuid.type = param_disc->uuid_len;
                xf_memcpy(svc_set[num].uuid.uuid128, param_disc->uuid, param_disc->uuid_len);
                port_msg_evt_clear_with_assert(index);
                ++num;
            }
        }
        XF_LOGD(TAG,"DISC ALL SVC CMPLT");   
    }
    else
    {
        return XF_ERR_NOT_FOUND;
    }
    service_set_info->set = svc_set;
    return XF_OK;
}

/**
 * @brief BLE GATTC 搜寻特征（指定 UUID 或 尝试搜寻所有特征）
 *
 * @param app_id 客户端 ID (应用 ID)
 * @param conn_id 连接 ID (链接 ID )
 * @param start_handle 服务起始句柄
 * @param end_handle 服务结束句柄
 * @param chara_uuid 指定搜寻的服务的 UUID，见 @ref xf_ble_uuid_info_t
 * @param [in,out] chara_set_info 传入将存储特征集合信息的地址。
 *  见 @ref xf_ble_gattc_chara_found_set_t ，例：
 * @code
 *  xf_ble_gattc_chara_found_set_t chara_set_info = {0};
 *  ......
 *  xf_ble_gattc_discover_chara(s_app_id, s_conn_id, svc->start_hdl, svc->end_hdl, NULL, &chara_set_info);
 * @endcode
 * @return xf_err_t
 *      - XF_OK                 成功
 *      - XF_FAIL               失败
 *      - (OTHER)               @ref xf_err_t
 */
xf_err_t xf_ble_gattc_discover_chara(
    uint8_t app_id, uint16_t conn_id,
    uint16_t start_handle,
    uint16_t end_handle,
    xf_ble_uuid_info_t *chara_uuid,
    xf_ble_gattc_chara_found_set_t *chara_set_info)
{
    XF_ASSERT(chara_set_info != NULL, XF_ERR_INVALID_ARG,
             TAG, "chara_set_info == NULL");
    XF_ASSERT(
            (start_handle != XF_BLE_ATTR_HANDLE_INVALID) 
        &&  (end_handle != XF_BLE_ATTR_HANDLE_INVALID), XF_ERR_INVALID_ARG,
        TAG, "handle([%#04X,%#04X]) invalid![0x0001,0xFFFF]", start_handle, end_handle);

    xf_ble_gattc_chara_found_t *chara_set = NULL;
    if(chara_uuid == NULL)
    {
        XF_LOGD(TAG,"DISC ALL CHARA START");   
        gatt_disc(conn_id, GATT_DISC_ALL_CHAR, start_handle, end_handle, 0, NULL);

        /* 检查是否有发现所有特征完成的事件 */
        port_msg_evt_get_with_check_and_clear( 
            PORT_MSG_EVT_BLE_GATT_DISC_CHARA_ALL_CMPLT, 100); 

        port_msg_info_t **list_msg_info = port_msg_info_list_get();
        
        uint8_t index = 0;
        uint8_t num = 0;
        /* 遍历事件信息列表，获取发现的服务数量 */
        for(;index < MSG_INFO_LIST_MAX_CNT; index++)
        {
            if(list_msg_info[index] == NULL)
            {
                continue;
            }    
            if( (list_msg_info[index]->grp_type == PORT_MSG_GRP_TYPE_GATT)
            &&  (list_msg_info[index]->msg_index == MSG_IDX(GATT_DISC_CHAR_IND)) )
            {
                ++num;
            }
        }

        chara_set_info->cnt = num;
        if (num == 0)
        {
            XF_LOGD(TAG,"DISC NO CHARA");   
            return XF_OK;
        }

        chara_set = xf_malloc(num * sizeof(xf_ble_gattc_chara_found_t));
        
        index = 0;
        num = 0;
        /* 检查消息的信息列表是否有匹配的 消息类型及消息索引 */
        for(;index < MSG_INFO_LIST_MAX_CNT; index++)
        {
            if(list_msg_info[index] == NULL)
            {
                continue;
            }    
            if( (list_msg_info[index]->grp_type == PORT_MSG_GRP_TYPE_GATT)
            &&  (list_msg_info[index]->msg_index == MSG_IDX(GATT_DISC_CHAR_IND)) )
            {
                struct gatt_disc_char_ind *param_disc = (struct gatt_disc_char_ind *)list_msg_info[index]->param; 

                XF_LOGD(TAG, "DISC CHARA:uuid:%#X,att_hdl:%d,hdl:%d,porp:%d,uuid_len:%d,%p",
                    *((uint16_t *)&param_disc->uuid[0]),
                    param_disc->attr_hdl,
                    param_disc->pointer_hdl,
                    param_disc->prop,
                    param_disc->uuid_len, chara_set);

                chara_set[num].desc_set_info.cnt = 0;
                chara_set[num].desc_set_info.set = NULL;
                chara_set[num].handle = param_disc->attr_hdl;
                chara_set[num].value_handle = param_disc->pointer_hdl;
                chara_set[num].props = param_disc->prop;   // 待确认
                chara_set[num].uuid.type = param_disc->uuid_len;
                xf_memcpy(chara_set[num].uuid.uuid128, param_disc->uuid, param_disc->uuid_len);
                port_msg_evt_clear_with_assert(index);
                ++num;
            }
        }
        XF_LOGD(TAG,"DISC ALL CHARA CMPLT");   
    }
    else
    {
        return XF_ERR_NOT_FOUND;
    }
    chara_set_info->set = chara_set;
    return XF_OK;
}

/**
 * @brief BLE GATTC 通过句柄发起读请求
 *
 * @param app_id 客户端 ID (应用 ID)
 * @param conn_id 连接 ID (链接 ID )
 * @param handle 句柄
 * @return xf_err_t
 *      - XF_OK                 成功
 *      - XF_FAIL               失败
 *      - (OTHER)               @ref xf_err_t
 */
xf_err_t xf_ble_gattc_request_read_by_handle(
    uint8_t app_id, uint16_t conn_id,
    uint16_t handle)
{
    gatt_read(conn_id, handle, 4);
    /* FIXME 是否需要等回调确认 */
    return XF_OK;
}

/**
 * @brief BLE GATTC 通过 UUID 发起读请求
 *
 * @param app_id 客户端 ID (应用 ID)
 * @param conn_id 连接 ID (链接 ID )
 * @param start_handle 起始句柄
 * @param end_handle 结束句柄
 * @param uuid 指定的 UUID
 * @return xf_err_t
 *      - XF_OK                 成功
 *      - XF_FAIL               失败
 *      - (OTHER)               @ref xf_err_t
 */
xf_err_t xf_ble_gattc_request_read_by_uuid(
    uint8_t app_id, uint16_t conn_id,
    uint16_t start_handle,
    uint16_t end_handle,
    const xf_ble_uuid_info_t *uuid)
{
    gatt_read_by_uuid(conn_id, (uint8_t)uuid->type, 
        (uint8_t *)uuid->uuid128, start_handle, end_handle);
    /* FIXME 是否需要等回调确认 */
    return XF_OK;
}

/**
 * @brief BLE GATTC 发起写请求
 *
 * @param app_id 客户端 ID (应用 ID)
 * @param conn_id 连接 ID (链接 ID )
 * @param handle 句柄
 * @param value 要写的数据
 * @param value_len 要写的数据的长度
 * @param write_type 写请求类型，见 @ref xf_ble_gattc_write_type_t
 * @return xf_err_t
 *      - XF_OK                 成功
 *      - XF_FAIL               失败
 *      - (OTHER)               @ref xf_err_t
 */
xf_err_t xf_ble_gattc_request_write(
    uint8_t app_id, uint16_t conn_id,
    uint16_t handle,
    uint8_t *value,
    uint16_t value_len,
    xf_ble_gattc_write_type_t write_type)
{
    gatt_write(conn_id, s_map_gattc_write_tyep[write_type],
        handle, value, value_len);
    /* FIXME 是否需要等回调确认 */
    return XF_OK;
}

/**
 * @brief BLE GATTC 发送 MTU 协商
 *
 * @param app_id 客户端 ID (应用 ID)
 * @param conn_id 连接 ID (链接 ID )
 * @param mtu_size 协商的 MTU 大小
 * @return xf_err_t
 *      - XF_OK                 成功
 *      - XF_FAIL               失败
 *      - (OTHER)               @ref xf_err_t
 */
xf_err_t xf_ble_gattc_request_exchange_mtu(
    uint8_t app_id, uint16_t conn_id,
    uint16_t mtu_size);

/**
 * @brief BLE GATTC 事件回调注册
 *
 * @param evt_cb 事件回调，见 @ref xf_ble_gattc_evt_cb_t
 * @param events 事件，见 @ref xf_ble_gattc_evt_t
 * @note 当前仅支持所有事件注册在同一个回调，暂不支持指定事件对应单独的回调，
 * 所以 参数 'events' 填 0 即可
 * @return xf_err_t
 *      - XF_OK                 成功
 *      - XF_FAIL               失败
 *      - (OTHER)               @ref xf_err_t
 */
xf_err_t xf_ble_gattc_event_cb_register(
    xf_ble_gattc_evt_cb_t evt_cb,
    xf_ble_gattc_evt_t events)
{
    s_ble_gattc_evt_cb = evt_cb;
    return XF_OK;
}

xf_ble_gattc_evt_cb_t port_xf_ble_gattc_event_cb_get(void)
{
    return s_ble_gattc_evt_cb;
}

port_msg_early_handler_status_t port_msg_early_handler_gatt_cmplt_evt(
    uint8_t conn_id, const port_msg_param_var_t *param)
{
    const struct gatt_cmp_evt *msg_param = &param->gatt_cmp_evt;
    enum gatt_operation operation = (enum gatt_operation)msg_param->operation;
    UNUSED(operation);
    XF_LOGD(TAG,"[EARLY]:GATT CMPLT:conn_id:%d,opt:%d,status:%d,seq_num:%d",
        conn_id, operation, msg_param->status, msg_param->seq_num);

    return PORT_MSG_EARLY_HANDLER_STATUS_RECORD;
}

port_msg_early_handler_status_t port_msg_early_handler_gatt_client_read_rsp(
    uint8_t conn_id, const port_msg_param_var_t *param)
{
    const struct gatt_read_ind *msg_param = &param->gatt_read_ind;

    XF_LOGD(TAG,"[EARLY]:GATTC READ RSP:conn_id:%d,hdl:%d,value_len:%d,offset:%d",
        conn_id, msg_param->handle, msg_param->length, msg_param->offset);

    port_ble_app_t *app = port_gatt_app_get_by_conn_id(conn_id);

    xf_ble_gattc_evt_cb_param_t evt_param = 
    {
        .read_cfm = {
            .app_id = app->app_id,
            .conn_id = conn_id,
            .handle = msg_param->handle,
            .value_len = msg_param->length,
            .value = (uint8_t *)msg_param->value,
        }
    };

    s_ble_gattc_evt_cb(XF_BLE_GATTC_EVT_READ_CFM, &evt_param);

    return PORT_MSG_EARLY_HANDLER_STATUS_CMPLT;
}


// port_msg_early_handler_status_t port_msg_early_handler_gatt_clinet_write_cfm(
//     uint8_t conn_id, const port_msg_param_var_t *param)
// {
//     const struct gatt_event_cfm *msg_param = &param->gatt_cmp_evt;

//     XF_LOGD(TAG,"[EARLY]:GATTC WRITE CFM:conn_id:%d,type:%d,hdl:%d,value_len:%d",
//         conn_id, msg_param->type, msg_param->handle, msg_param->length);

//     // port_ble_app_t *app = port_gatt_app_get_by_conn_id(conn_id);

//     // xf_ble_gattc_evt_cb_param_t evt_param = 
//     // {
//     //     .write_cfm = {
//     //         .app_id = app->app_id,
//     //         .conn_id = conn_id,
//     //         .handle = msg_param->handle,
//     //         .offset = msg_param
//     //     }
//     // } 

//     // s_ble_gattc_evt_cb(GATT_EVENT_CFM, &evt_param);

//     return PORT_MSG_EARLY_HANDLER_STATUS_RECORD;
// }


/* ==================== [Static Functions] ================================== */

/**
 * @brief 仅用于默认的事件回调函数
 *  这样可以不再在各调用处检查 s_ble_gattc_evt_cb 的有效性
 */
xf_err_t _default_ble_gattc_evt_cb(
    xf_ble_gattc_evt_t event,
    xf_ble_gattc_evt_cb_param_t *param)
{
    return XF_OK;
}

#endif
